transform: Add gsk_transform_parse()
authorBenjamin Otte <otte@redhat.com>
Thu, 21 Mar 2019 04:52:41 +0000 (05:52 +0100)
committerBenjamin Otte <otte@redhat.com>
Fri, 12 Apr 2019 17:34:29 +0000 (19:34 +0200)
It uses the new CSS parser.

docs/reference/gsk/gsk4-sections.txt
gsk/gsktransform.c
gsk/gsktransform.h
gsk/gsktransformprivate.h

index e3b3151c57bb857c3a8e2f47d1d886b6df9ba234..35d042fc5c8cc9345576603331917e4b3403ea67 100644 (file)
@@ -152,6 +152,8 @@ gsk_transform_get_category
 <SUBSECTION>
 gsk_transform_print
 gsk_transform_to_string
+gsk_transform_parse
+<SUBSECTION>
 gsk_transform_to_matrix
 gsk_transform_to_2d
 gsk_transform_to_affine
index d5e4ac4e5a1a32232c86652cd99f15e38d8534ea..1dfd9b9740031818473dd7318c671ce4951d1fa7 100644 (file)
@@ -1264,8 +1264,8 @@ gsk_transform_unref (GskTransform *self)
  * @self: (allow-none): a #GskTransform
  * @string:  The string to print into
  *
- * Converts @self into a string representation suitable for printing that
- * can later be parsed with gsk_transform_parse().
+ * Converts @self into a human-readable string representation suitable
+ * for printing that can later be parsed with gsk_transform_parse().
  **/
 void
 gsk_transform_print (GskTransform *self,
@@ -1651,3 +1651,258 @@ gsk_transform_transform_bounds (GskTransform          *self,
       break;
     }
 }
+
+static guint
+gsk_transform_parse_float (GtkCssParser *parser,
+                           guint         n,
+                           gpointer      data)
+{
+  float *f = data;
+  double d;
+
+  if (!gtk_css_parser_consume_number (parser, &d))
+    return 0;
+
+  f[n] = d;
+  return 1;
+}
+
+static guint
+gsk_transform_parse_scale (GtkCssParser *parser,
+                           guint         n,
+                           gpointer      data)
+{
+  float *f = data;
+  double d;
+
+  if (!gtk_css_parser_consume_number (parser, &d))
+    return 0;
+
+  f[n] = d;
+  f[1] = d;
+  return 1;
+}
+
+gboolean
+gsk_transform_parser_parse (GtkCssParser  *parser,
+                            GskTransform **out_transform)
+{
+  const GtkCssToken *token;
+  GskTransform *transform = NULL;
+  float f[16] = { 0, };
+
+  token = gtk_css_parser_get_token (parser);
+  if (gtk_css_token_is_ident (token, "none"))
+    {
+      gtk_css_parser_consume_token (parser);
+      *out_transform = NULL;
+      return TRUE;
+    }
+
+  while (TRUE)
+    {
+      if (gtk_css_token_is_function (token, "matrix"))
+        {
+          graphene_matrix_t matrix;
+          if (!gtk_css_parser_consume_function (parser, 6, 6, gsk_transform_parse_float, f))
+            goto fail;
+
+          graphene_matrix_init_from_2d (&matrix, f[0], f[1], f[2], f[3], f[4], f[5]);
+          transform = gsk_transform_matrix_with_category (transform,
+                                                          &matrix,
+                                                          GSK_TRANSFORM_CATEGORY_2D);
+        }
+      else if (gtk_css_token_is_function (token, "matrix3d"))
+        {
+          graphene_matrix_t matrix;
+          if (!gtk_css_parser_consume_function (parser, 16, 16, gsk_transform_parse_float, f))
+            goto fail;
+
+          graphene_matrix_init_from_float (&matrix, f);
+          transform = gsk_transform_matrix (transform, &matrix);
+        }
+      else if (gtk_css_token_is_function (token, "perspective"))
+        {
+          if (!gtk_css_parser_consume_function (parser, 1, 1, gsk_transform_parse_float, f))
+            goto fail;
+
+          transform = gsk_transform_perspective (transform, f[0]);
+        }
+      else if (gtk_css_token_is_function (token, "rotate") ||
+               gtk_css_token_is_function (token, "rotateZ"))
+        {
+          if (!gtk_css_parser_consume_function (parser, 1, 1, gsk_transform_parse_float, f))
+            goto fail;
+
+          transform = gsk_transform_rotate (transform, f[0]);
+        }
+      else if (gtk_css_token_is_function (token, "rotate3d"))
+        {
+          graphene_vec3_t axis;
+
+          if (!gtk_css_parser_consume_function (parser, 4, 4, gsk_transform_parse_float, f))
+            goto fail;
+
+          graphene_vec3_init (&axis, f[0], f[1], f[2]);
+          transform = gsk_transform_rotate_3d (transform, f[3], &axis);
+        }
+      else if (gtk_css_token_is_function (token, "rotateX"))
+        {
+          if (!gtk_css_parser_consume_function (parser, 1, 1, gsk_transform_parse_float, f))
+            goto fail;
+
+          transform = gsk_transform_rotate_3d (transform, f[0], graphene_vec3_x_axis ());
+        }
+      else if (gtk_css_token_is_function (token, "rotateY"))
+        {
+          if (!gtk_css_parser_consume_function (parser, 1, 1, gsk_transform_parse_float, f))
+            goto fail;
+
+          transform = gsk_transform_rotate_3d (transform, f[0], graphene_vec3_y_axis ());
+        }
+      else if (gtk_css_token_is_function (token, "scale"))
+        {
+          if (!gtk_css_parser_consume_function (parser, 1, 2, gsk_transform_parse_scale, f))
+            goto fail;
+
+          transform = gsk_transform_scale (transform, f[0], f[1]);
+        }
+      else if (gtk_css_token_is_function (token, "scale3d"))
+        {
+          if (!gtk_css_parser_consume_function (parser, 3, 3, gsk_transform_parse_float, f))
+            goto fail;
+
+          transform = gsk_transform_scale_3d (transform, f[0], f[1], f[2]);
+        }
+      else if (gtk_css_token_is_function (token, "scaleX"))
+        {
+          if (!gtk_css_parser_consume_function (parser, 1, 1, gsk_transform_parse_float, f))
+            goto fail;
+
+          transform = gsk_transform_scale (transform, f[0], 1.f);
+        }
+      else if (gtk_css_token_is_function (token, "scaleY"))
+        {
+          if (!gtk_css_parser_consume_function (parser, 1, 1, gsk_transform_parse_float, f))
+            goto fail;
+
+          transform = gsk_transform_scale (transform, 1.f, f[0]);
+        }
+      else if (gtk_css_token_is_function (token, "scaleZ"))
+        {
+          if (!gtk_css_parser_consume_function (parser, 1, 1, gsk_transform_parse_float, f))
+            goto fail;
+
+          transform = gsk_transform_scale_3d (transform, 1.f, 1.f, f[0]);
+        }
+      else if (gtk_css_token_is_function (token, "translate"))
+        {
+          f[1] = 0.f;
+          if (!gtk_css_parser_consume_function (parser, 1, 2, gsk_transform_parse_float, f))
+            goto fail;
+
+          transform = gsk_transform_translate (transform, &GRAPHENE_POINT_INIT (f[0], f[1]));
+        }
+      else if (gtk_css_token_is_function (token, "translate3d"))
+        {
+          if (!gtk_css_parser_consume_function (parser, 3, 3, gsk_transform_parse_float, f))
+            goto fail;
+
+          transform = gsk_transform_translate_3d (transform, &GRAPHENE_POINT3D_INIT (f[0], f[1], f[2]));
+        }
+      else if (gtk_css_token_is_function (token, "translateX"))
+        {
+          if (!gtk_css_parser_consume_function (parser, 1, 1, gsk_transform_parse_float, f))
+            goto fail;
+
+          transform = gsk_transform_translate (transform, &GRAPHENE_POINT_INIT (f[0], 0.f));
+        }
+      else if (gtk_css_token_is_function (token, "translateY"))
+        {
+          if (!gtk_css_parser_consume_function (parser, 1, 1, gsk_transform_parse_float, f))
+            goto fail;
+
+          transform = gsk_transform_translate (transform, &GRAPHENE_POINT_INIT (0.f, f[0]));
+        }
+      else if (gtk_css_token_is_function (token, "translateZ"))
+        {
+          if (!gtk_css_parser_consume_function (parser, 1, 1, gsk_transform_parse_float, f))
+            goto fail;
+
+          transform = gsk_transform_translate_3d (transform, &GRAPHENE_POINT3D_INIT (0.f, 0.f, f[0]));
+        }
+#if 0
+      /* FIXME: add these */
+      else if (gtk_css_token_is_function (token, "skew"))
+        {
+        }
+      else if (gtk_css_token_is_function (token, "skewX"))
+        {
+        }
+      else if (gtk_css_token_is_function (token, "skewY"))
+        {
+        }
+#endif
+      else
+        {
+          break;
+        }
+
+      token = gtk_css_parser_get_token (parser);
+    }
+
+  if (transform == NULL)
+    {
+      gtk_css_parser_error_syntax (parser, "Expected a transform");
+      goto fail;
+    }
+
+  *out_transform = transform;
+  return TRUE;
+
+fail:
+  gsk_transform_unref (transform);
+  *out_transform = NULL;
+  return FALSE;
+}
+
+/**
+ * gsk_transform_parse:
+ * @string: the string to parse
+ * @out_transform: (out): The location to put the transform in
+ *
+ * Parses the given @string into a transform and puts it in
+ * @out_transform. Strings printed via gsk_transform_to_string()
+ * can be read in again successfully using this function.
+ *
+ * If @string does not describe a valid transform, %FALSE is
+ * returned and %NULL is put in @out_transform.
+ *
+ * Returns: %TRUE if @string described a valid transform.
+ **/
+gboolean
+gsk_transform_parse (const char    *string,
+                     GskTransform **out_transform)
+{
+  GtkCssParser *parser;
+  GBytes *bytes;
+  gboolean result;
+
+  g_return_val_if_fail (string != NULL, FALSE);
+  g_return_val_if_fail (out_transform != NULL, FALSE);
+
+  bytes = g_bytes_new_static (string, strlen (string));
+  parser = gtk_css_parser_new_for_bytes (bytes, NULL, NULL, NULL, NULL, NULL);
+
+  result = gsk_transform_parser_parse (parser, out_transform);
+
+  if (result && !gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_EOF))
+    {
+      g_clear_pointer (out_transform, gsk_transform_unref);
+      result = FALSE;
+    }
+  gtk_css_parser_unref (parser);
+  g_bytes_unref (bytes);
+
+  return result; 
+}
index 6cbe3659f299d985eb29cd5bc2883fff94ad2b42..6ef7427448ae6f3dcbe047336854ceeb163a8457 100644 (file)
@@ -46,6 +46,9 @@ void                    gsk_transform_print                     (GskTransform
 GDK_AVAILABLE_IN_ALL
 char *                  gsk_transform_to_string                 (GskTransform                   *self);
 GDK_AVAILABLE_IN_ALL
+gboolean                gsk_transform_parse                     (const char                     *string,
+                                                                 GskTransform                  **out_transform);
+GDK_AVAILABLE_IN_ALL
 void                    gsk_transform_to_matrix                 (GskTransform                   *self,
                                                                  graphene_matrix_t              *out_matrix);
 GDK_AVAILABLE_IN_ALL
index 5ea45e03fb29e09f5a7e162597f94dc3d0f0b486..a276a640b3c2825f610da3c52c37886bd9fa4d96 100644 (file)
 
 #include "gsktransform.h"
 
-#include <gsk/gsk.h>
 #include "gsk/gskrendernodeprivate.h"
 
+#include <gtk/css/gtkcss.h>
+#include "gtk/css/gtkcssparserprivate.h"
+
 G_BEGIN_DECLS
 
 GskTransform *          gsk_transform_matrix_with_category      (GskTransform           *next,
                                                                  const graphene_matrix_t*matrix,
                                                                  GskTransformCategory    category);
 
+gboolean                gsk_transform_parser_parse              (GtkCssParser           *parser,
+                                                                 GskTransform          **out_transform);
+
+
 G_END_DECLS
 
 #endif /* __GSK_TRANSFORM_PRIVATE_H__ */